#include "besierspline.h"
#include <QPainter>
#include<QPainterPath>
#include<QMouseEvent>
#include<QEvent>
#include<QDebug>
#include<QFrame>


besierspline::besierspline(QWidget *parent) : QLabel(parent), state(1)
{
    setGeometry(0,43, parent->width(), parent->height()-43);
    show();
    //this->setFrameShape(Shape::Box);
}

void besierspline::enterEvent(QEvent *event)
{
    qDebug()<<"鼠标进入了";
    //this->setFrameShape(Shape::Box);
    //this->setStyleSheet("border-width: 1px;border-style: solid;border-color: rgb(255, 170, 0);");
    //QLabel::enterEvent(event);
}

void besierspline::leaveEvent(QEvent *event)
{
    qDebug()<<"鼠标离开了";
    //this->setFrameShape(Shape::NoFrame);
    //this->setStyleSheet("");
    //QLabel::leaveEvent(event);
}

void besierspline::mouseMoveEvent(QMouseEvent *ev)
{    
    QLabel::mouseMoveEvent(ev);
    QString str1 = QString("鼠标移动了 drag=%1")
            .arg(state);
    qDebug()<<str1;
    if(state==1){// 新建，点跟着鼠标移动
        controlPoints.back() = Eigen::Vector2f( ev->x(),ev->y());
        update();
        return;
    }
    if(!drag)return;
     str1 = QString("鼠标移动了 drag=%1")
            .arg(drag);
    //qDebug()<<str1;
    QString str = QString("鼠标移动了 x=%1, y=%2, globalX=%3, globalY=%4" )
            .arg(ev->x()).arg(ev->y())
            .arg(ev->globalX()).arg(ev->globalY());
    //qDebug()<<str;
    auto movement = ev->globalPos()-lastPos;
        lastPos = ev->globalPos();

        this->move(mapToParent( movement));
        update();
}

void besierspline::mousePressEvent(QMouseEvent *ev)
{
    if(ev->button()==Qt::MouseButton::LeftButton) {
        if(state==1){
            controlPoints.push_back(Eigen::Vector2f( ev->x(),ev->y()));
            update();
            return;
        }
        emit select(this);
        lastPos = ev->globalPos();
        drag=1;
    }else if(ev->button()==Qt::RightButton) {
        if(state==1) {
            state=0;
            updateBox();
        }
    }
}

void besierspline::mouseReleaseEvent(QMouseEvent *ev)
{
    if(ev->button()==Qt::MouseButton::LeftButton) {
        if(state==1) {
            // 新建添加点
            controlPoints.back() = Eigen::Vector2f( ev->x(),ev->y());
            update();
            return;
        }
    }
}


int besierspline::setControlPoints(const List2f &A)
{
    controlPoints=A;
    this->setGeometry(0,0, 10, 10);
    state = 0;
    updateBox();
}

void besierspline::chaikinSubdivide(int iter)
{
    if(iter<1)return;
    List2f res[2];

    res[0]=controlPoints;
    int pre=0;
    for(int i=0;i<iter;++i, pre^=1) {
        res[pre^1].resize(res[pre].size()*2);
        int n=res[pre].size();
        for(int j=0;j<res[pre].size(); ++j) {
            int j1=j+1, jn1=j-1;
            j1%=n;
            jn1 = (jn1+n)%n;
            V2f p = res[pre][j];
            V2f pn1 = res[pre][jn1];
            V2f p1 = res[pre][j1];
            res[pre^1][j*2]=1.0/8*pn1 + 3.0/4*p + 1.0/8*res[pre][j1];
            res[pre^1][j*2+1]=(p+p1)/2;
        }
    }

    showPoints = res[pre^1];

    update();

}

void besierspline::cubicSubdivide(int iter)
{
    if(iter<1)return;
    List2f res[2];

    res[0]=controlPoints;
    int pre=0;
    for(int i=0;i<iter;++i, pre^=1) {
        res[pre^1].resize(res[pre].size()*2);
        int n=res[pre].size();
        for(int j=0;j<res[pre].size(); ++j) {
            int j1=j+1, jn1=j-1;
            j1%=n;
            jn1 = (jn1+n)%n;
            V2f p = res[pre][j];
            V2f pn1 = res[pre][jn1];
            V2f p1 = res[pre][j1];
            res[pre^1][j*2]=1.0/4*pn1+ 3.0/4*p;
            res[pre^1][j*2+1]=3.0/4*p + 1.0/4*p1;
        }
    }

    showPoints = res[pre^1];

    update();
}

void besierspline::fittingSubdivide(int iter)
{
    if(iter<1)return;

    List2f res[2];

    res[0]=controlPoints;
    int pre=0;
    float alpha = 1.0/8;
    for(int i=0;i<iter;++i, pre^=1) {
        res[pre^1].resize(res[pre].size()*2);
        int n=res[pre].size();
        for(int j=0;j<res[pre].size(); ++j) {
            res[pre^1][j*2]=res[pre][j];
            int j1=j+1, j2=j+2, jn1=j-1;
            j1%=n;
            j2%=n;
            jn1 = (jn1+n)%n;
            V2f p = res[pre][j];
            V2f pn1 = res[pre][jn1];
            V2f p1 = res[pre][j1];
            V2f p2 = res[pre][j2];
            V2f newP = (p+p1)/2 + alpha*((p+p1)/2 - (pn1+p2)/2);
            res[pre^1][j*2+1]=newP;
        }
    }

    showPoints = res[pre^1];
    auto tl = this->geometry().topLeft();
    for(auto &p: showPoints){
       p.x()+= tl.x();
       p.y() += tl.y();
    }
    for(auto &p: controlPoints){
       p.x()+= tl.x();
       p.y() += tl.y();
    }
    QRect rect(showPoints[0].x(), showPoints[0].y(), 2, 2);

    for(auto &p: showPoints){
        if(p.y()< rect.top()) rect.setTop(p.y());
        if(p.y()> rect.bottom()) rect.setBottom(p.y());
        if(p.x()< rect.left()) rect.setLeft(p.x());
        if(p.x()> rect.right()) rect.setRight(p.x());
    }
    int offset = 10;
    rect.setTopLeft( rect.topLeft() - QPoint(offset, offset));
    rect.setBottomRight( rect.bottomRight() + QPoint(offset, offset));
    this->setGeometry(rect);
    tl = this->geometry().topLeft();
    for(auto &p: showPoints){
        p.x()-=tl.x();
        p.y() -= tl.y();
    }
    for(auto &p: controlPoints){
        p.x()-=tl.x();
        p.y() -= tl.y();
    }
    update();
}

void besierspline::updateBox()
{
    if(controlPoints.empty())return;
    auto tl = this->geometry().topLeft();
    for(auto &p: controlPoints){
       p.x()+= tl.x();
       p.y() += tl.y();
    }
    QRect rect(controlPoints[0].x(), controlPoints[0].y(), 2, 2);

    for(auto &p: controlPoints){
        if(p.y()< rect.top()) rect.setTop(p.y());
        if(p.y()> rect.bottom()) rect.setBottom(p.y());
        if(p.x()< rect.left()) rect.setLeft(p.x());
        if(p.x()> rect.right()) rect.setRight(p.x());
    }
    int offset = 10;
    rect.setTopLeft( rect.topLeft() - QPoint(offset, offset));
    rect.setBottomRight( rect.bottomRight() + QPoint(offset, offset));
    this->setGeometry(rect);
    tl = this->geometry().topLeft();
    for(auto &p: controlPoints){
        p.x()-=tl.x();
        p.y() -= tl.y();
    }
    update();
}

//绘图事件
void besierspline::paintEvent(QPaintEvent *event){
    QWidget::paintEvent(event);
    // qDebug()<<"画画";
    QPainter painter(this);
    QPen pen;

    // 画点
    pen.setWidth(10);
    pen.setColor(Qt::red);
    painter.setPen(pen);
    for(auto &p:controlPoints) {
        painter.drawPoint(QPoint(p.x(), p.y()));
    }

    pen.setColor(Qt::black);
    pen.setWidth(1);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
    for(int i=0;i<showPoints.size();++i){
        int j = (i+1)%showPoints.size();
        painter.drawLine(QPoint(showPoints[i].x(), showPoints[i].y()),QPoint(showPoints[j].x(), showPoints[j].y()));
    }

    pen.setColor(Qt::blue);
    pen.setStyle(Qt::DashLine);
    painter.setPen(pen);

    for(int i=0;i<controlPoints.size();++i) {
        int j = (i+1)%controlPoints.size();
        painter.drawLine(QPoint(controlPoints[i].x(), controlPoints[i].y()), QPoint(controlPoints[j].x(), controlPoints[j].y()));
    }
}
